import { TYPES } from '@2/app/core/ioc/types';
import { UserService } from '@2/app/core/services/user.service';
import { Oauth2Token, SocialToken } from '@2/typings/oauth2';

import { ErrorMessageMode } from '#/axios';
import { inject, injectable } from 'inversify';
import { PermissionStorage } from '@2/app/core/storage/permission.storage';
import { PermissionService } from '@2/app/core/services/permission.service';
import { UserStorage } from '@2/app/core/storage/user.storage';
import { ApiAuth } from '@2/app/core/api/api.auth';
import { AppUser } from '@2/typings/model/app.user';
import { router } from '@/router';
import { RouteRecordRaw } from 'vue-router';
import { PAGE_NOT_FOUND_ROUTE } from '@/router/routes/basic';
import { PageEnum } from '@/enums/pageEnum';
import { TOKEN_EFFECTIVE_DURATION } from '@2/typings/constant/cache.c';
import { LoginModel } from '@2/typings/model/login.model';
import { useMessage } from '@/hooks/web/useMessage';
import { useI18n } from 'vue-i18n';
import { h } from 'vue';
import { ApiUser } from '@2/app/core/api/api.user';

/**
 * @program: microservice-central-portal
 * @description: 用户登录服务实现
 * @author: baiHoo.chen
 * @create: 2022年5月26日
 **/
@injectable()
export class UserServiceImpl implements UserService {
  constructor(
    @inject(TYPES.PermissionStorage) protected permissionStorage: PermissionStorage,
    @inject(TYPES.PermissionService) protected permissionService: PermissionService,
    @inject(TYPES.UserStorage) protected userStorage: UserStorage,
    @inject(TYPES.ApiAuth) protected apiAuth: ApiAuth,
    @inject(TYPES.ApiUser) protected apiUser: ApiUser,
  ) {}

  async afterLoginAction(goHome?: boolean): Promise<AppUser | null> {
    if (!this.userStorage.getToken()) return null;
    // 1. 获取用户执行信息
    const userInfo = this.userStorage.getAppUser();
    // 2. 判断 session 是否过期
    const sessionTimeout = this.userStorage.isSessionNonExpired();
    if (sessionTimeout) {
      this.userStorage.setSessionNonExpired(true);
    } else {
      if (!this.permissionStorage.isDynamicAddedRoute()) {
        // 动态设置权限路由
        const routes = await this.permissionService.buildRoutesAction();
        routes.forEach((route) => {
          router.addRoute(route as unknown as RouteRecordRaw);
        });
        router.addRoute(PAGE_NOT_FOUND_ROUTE as unknown as RouteRecordRaw);
        this.permissionStorage.setDynamicAddedRoute(true);
      }
      goHome && (await router.replace(userInfo?.homePath || PageEnum.BASE_HOME));
    }
    return userInfo;
  }
  async getAppUser(): Promise<AppUser | null> {
    if (!this.userStorage.getToken()) return null;
    return this.userStorage.getAppUser();
  }
  /**
   * 用户登录
   * @param params
   */
  async login(
    params: LoginModel & { goHome?: boolean; mode?: ErrorMessageMode },
  ): Promise<AppUser | any> {
    const { goHome = true, ...loginParams } = params;
    const result: Oauth2Token = await this.apiAuth.login(loginParams, params.mode);
    // 优先设置用户登录 TOKEN信息
    this.userStorage.setToken({
      token: result.access_token,
      refreshToken: result.refresh_token.value,
      clientExpiration: Date.now() + TOKEN_EFFECTIVE_DURATION,
    });
    // 获取用户信息
    const appUser: AppUser = await this.apiUser.getByUsername(params.username);
    appUser.menus = await this.apiUser.getUserMenus(appUser.id);
    // 权限缓存设置
    this.permissionStorage.setAuthorities(appUser.permissions);
    // 设置用户缓存
    this.userStorage.setAppUser(appUser);
    // 登录成功后执行器设置
    return await this.afterLoginAction(goHome);
  }
  confirmLoginOut() {
    const { createConfirm } = useMessage();
    const { t } = useI18n();
    createConfirm({
      iconType: 'warning',
      title: () => h('span', t('sys.app.logoutTip')),
      content: () => h('span', t('sys.app.logoutMessage')),
      onOk: async () => {
        await this.logout(true);
      },
    });
  }
  async validateJwtToken(doRefresh: boolean) {
    // @ts-ignore
    const socialToken: SocialToken = this.userStorage.getToken();
    if (doRefresh && !this.isTokenValid(socialToken)) {
      try {
        // @ts-ignore
        const res = await this.apiAuth.refreshToken(socialToken.refreshToken);
        // 优先设置用户登录 TOKEN信息
        this.userStorage.setToken({
          token: res.token,
          refreshToken: res.refreshToken,
          clientExpiration: Date.now() + TOKEN_EFFECTIVE_DURATION,
        });
      } catch (e) {
        this.userStorage.destroy();
        await router.push(PageEnum.BASE_LOGIN);
      }
    }
  }
  isTokenValid(socialToken?: SocialToken): boolean {
    if (!socialToken) {
      socialToken = this.userStorage.getToken();
    }
    if (socialToken && socialToken.clientExpiration) {
      return socialToken.clientExpiration > Date.now();
    } else {
      return false;
    }
  }
  async logout(goLogin: boolean) {
    if (this.userStorage.getToken()) {
      try {
        // 注销登录方法
        await this.apiAuth.logout();
      } catch {
        console.log('注销Token失败');
      }
    }
    this.userStorage.destroy();
    goLogin && (await router.push(PageEnum.BASE_LOGIN));
  }
}
